package com.symaster.pdfcompose.frame.page;

import com.intellij.uiDesigner.core.GridLayoutManager;
import com.symaster.pdfcompose.config.Data;
import com.symaster.pdfcompose.entity.ResultItemEntity;
import com.symaster.pdfcompose.frame.component.pdfpanel.PdfPanel;
import com.symaster.pdfcompose.frame.component.pdfpanel.ResultItem;
import com.symaster.pdfcompose.frame.component.pdfpanel.SourceItem;
import com.symaster.pdfcompose.frame.component.pdfrow.PdfRow;
import com.symaster.pdfcompose.frame.component.scrollbar.Scrollbar;
import com.symaster.pdfcompose.frame.component.tabs.TabCard;
import com.symaster.pdfcompose.util.PDFUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.pdfbox.multipdf.PDFMergerUtility;

import javax.swing.*;
import javax.swing.border.TitledBorder;
import java.awt.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.event.ActionEvent;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author yinmiao
 * @version 2024/4/28
 */
public class PdfAppend extends TabCard {
    private final PdfPanel pdfList;
    private static final ThreadPoolExecutor pool = new ThreadPoolExecutor(1, 1, 0, TimeUnit.SECONDS, new ArrayBlockingQueue<>(1024));
    private final PdfPanel resultList;

    private JPanel root_panel;
    private JPanel center_list;
    private JPanel option_bar;
    private JPanel right_panel;
    private final Data data;

    public PdfAppend(Data data) {
        this.data = data;
        pdfList = new PdfPanel();
        resultList = new PdfPanel();

        center_list.setBorder(new TitledBorder("文件列表"));

        right_panel.setBorder(new TitledBorder("拼接队列"));

        Scrollbar scrollbar = new Scrollbar(pdfList);

        center_list.add(scrollbar);

        JPanel jPanel = new JPanel();
        jPanel.setLayout(new FlowLayout());

        JButton startBtn = new JButton("开始合成");
        startBtn.addActionListener(this::startListener);
        jPanel.add(startBtn);

        option_bar.add(jPanel, BorderLayout.EAST);

        Scrollbar scrollbar1 = new Scrollbar(resultList);
        right_panel.add(scrollbar1);

        initListener();
    }

    private static List<File> getFiles(Transferable transferable) throws UnsupportedFlavorException, IOException {
        List<File> files = null;
        Object transferData = transferable.getTransferData(DataFlavor.javaFileListFlavor);
        if (transferData instanceof List) {
            files = ((List<?>) transferData).stream()
                    .filter(e -> e instanceof File)
                    .map(e -> (File) e)
                    .filter(PdfAppend::filterFile)
                    .collect(Collectors.toList());
        }
        return files;
    }

    private static boolean isImage(File file1) {
        String fileType = getFileType(file1);
        if (fileType == null) {
            throw new IllegalArgumentException("异常");
        }

        return "jpg".equalsIgnoreCase(fileType) ||
                "tif".equalsIgnoreCase(fileType) ||
                "jpeg".equalsIgnoreCase(fileType) ||
                "png".equalsIgnoreCase(fileType);
    }

    public static boolean filterFile(File file) {
        if (file == null) {
            return false;
        }
        if (!file.isFile()) {
            return false;
        }

        String substring = getFileType(file);
        if (substring == null) return false;

        return isImage(file) || "pdf".equalsIgnoreCase(substring);
    }

    private static String getFileType(File file) {
        String name = file.getName();
        if (StringUtils.isEmpty(name)) {
            return null;
        }
        int i = name.lastIndexOf(".");
        if (i < 0) {
            return null;
        }
        return name.substring(i + 1);
    }

    private void startListener(ActionEvent actionEvent) {
        List<File> collect = Arrays.stream(pdfList.getComponents()).filter(e -> {
            if (e instanceof SourceItem) {
                SourceItem sourceItem = (SourceItem) e;
                JComponent component = sourceItem.getComponent();
                if (component instanceof PdfRow) {
                    PdfRow pdfRow = (PdfRow) component;
                    File pdfFile = pdfRow.getPdfFile();
                    return pdfFile.isFile();
                }
            }
            return false;
        }).map(e -> {
            SourceItem sourceItem = (SourceItem) e;
            PdfRow pdfRow = (PdfRow) sourceItem.getComponent();
            return pdfRow.getPdfFile();
        }).collect(Collectors.toList());

        if (collect.isEmpty()) {
            return;
        }

        SwingUtilities.invokeLater(() -> {
            pdfList.setVisible(false);
            pdfList.removeAll();
            pdfList.setVisible(true);
        });

        File file = new File("out" + File.separator + new Date().getTime() + ".pdf").getAbsoluteFile();

        String id = UUID.randomUUID().toString();
        PdfRow pdfRow = new PdfRow(file);
        ResultItem resultItem = new ResultItem(pdfRow, () -> delete(id));
        resultItem.setStatus(ResultItem.Status.EXEC);

        SwingUtilities.invokeLater(() -> {
            resultList.setVisible(false);
            resultList.add(resultItem, 0);
            resultList.setVisible(true);
        });

        append(collect, file, resultItem, id);
    }

    private void append(List<File> collect, File file, ResultItem resultItem, String id) {
        pool.execute(() -> {
            try {
                File parentFile = file.getParentFile();
                if (parentFile != null) {
                    if (!parentFile.isDirectory() && !parentFile.mkdirs()) {
                        throw new RuntimeException(parentFile.getPath());
                    }
                }

                PDFMergerUtility pdfMerger = new PDFMergerUtility();
                for (File file1 : collect) {
                    if (isImage(file1)) {
                        pdfMerger.addSource(PDFUtil.toPDF(file1.getPath()));
                    } else {
                        pdfMerger.addSource(file1);
                    }
                }
                pdfMerger.setDestinationFileName(file.getPath());
                pdfMerger.mergeDocuments(null);
                resultItem.setStatus(ResultItem.Status.RESULT);

                ResultItemEntity resultItemEntity = new ResultItemEntity();
                resultItemEntity.setFilePath(file.getPath());
                resultItemEntity.setId(id);
                PdfAppend.this.data.fastPutArray("resultList", resultItemEntity);

            } catch (IOException e) {
                e.printStackTrace(System.err);
                resultItem.setStatus(ResultItem.Status.FIL);
            }
        });
    }

    private void addFileListener(ActionEvent actionEvent) {

    }

    private void delete(String id) {
        List<ResultItemEntity> resultList1 = data.getArray("resultList", ResultItemEntity.class);
        if (resultList1 != null && !resultList1.isEmpty()) {
            int index = -1;
            for (int i = 0; i < resultList1.size(); i++) {
                ResultItemEntity resultItemEntity = resultList1.get(i);
                if (StringUtils.isNotEmpty(resultItemEntity.getId()) && resultItemEntity.getId().equals(id)) {
                    index = i;
                }
            }
            if (index >= 0) {
                data.delByIndex("resultList", index);
            }
        }
    }

    public void loadResultList() {

        List<ResultItemEntity> resultList1 = data.getArray("resultList", ResultItemEntity.class);
        if (resultList1 != null && !resultList1.isEmpty()) {
            SwingUtilities.invokeLater(() -> {
                resultList.setVisible(false);
                for (ResultItemEntity itemEntity : resultList1) {
                    File file = new File(itemEntity.getFilePath());
                    ResultItem resultItem = new ResultItem(new PdfRow(file), () -> delete(itemEntity.getId()));

                    if (file.isFile()) {
                        resultItem.setStatus(ResultItem.Status.RESULT);
                    } else {
                        resultItem.setStatus(ResultItem.Status.NOT_FOUNT);
                    }

                    resultList.add(resultItem);
                }
                resultList.setVisible(true);
            });
        }
    }

    private void initListener() {
        // 拖动文件事件
        center_list.setDropTarget(new DropTarget() {
            public void drop(DropTargetDropEvent evt) {
                dropListener(evt);
            }
        });

        // 尺寸改变事件
        root_panel.addComponentListener(new ComponentAdapter() {
            @Override
            public void componentResized(ComponentEvent e) {

                // 维持右边结果列表的宽度始终为 50%
                int round = Math.round(root_panel.getWidth() / 2f);
                int height = right_panel.getHeight();
                right_panel.setPreferredSize(new Dimension(round, height));
            }
        });
    }

    public synchronized void dropListener(DropTargetDropEvent evt) {
        try {
            evt.acceptDrop(DnDConstants.ACTION_COPY);
            Transferable transferable = evt.getTransferable();
            if (transferable.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {

                List<File> files = getFiles(transferable);

                if (files != null && !files.isEmpty()) {
                    addFiles(files);
                }
            }
        } catch (Exception e) {
            e.printStackTrace(System.err);
        }
    }

    private void addFiles(List<File> files) {
        SwingUtilities.invokeLater(() -> {
            pdfList.setVisible(false);
            for (File file : files) {
                pdfList.add(new SourceItem(new PdfRow(file)));
            }
            pdfList.setVisible(true);
        });
    }

    @Override
    public Container container() {
        return root_panel;
    }

    @Override
    public String title() {
        return "PDF拼接";
    }

    @Override
    public String key() {
        return "PdfAppend";
    }

    {
// GUI initializer generated by IntelliJ IDEA GUI Designer
// >>> IMPORTANT!! <<<
// DO NOT EDIT OR ADD ANY CODE HERE!
        $$$setupUI$$$();
    }

    /**
     * Method generated by IntelliJ IDEA GUI Designer
     * >>> IMPORTANT!! <<<
     * DO NOT edit this method OR call it in your code!
     *
     * @noinspection ALL
     */
    private void $$$setupUI$$$() {
        root_panel = new JPanel();
        root_panel.setLayout(new BorderLayout(0, 0));
        final JPanel panel1 = new JPanel();
        panel1.setLayout(new GridLayoutManager(1, 1, new Insets(0, 0, 0, 0), -1, -1));
        root_panel.add(panel1, BorderLayout.NORTH);
        option_bar = new JPanel();
        option_bar.setLayout(new BorderLayout(0, 0));
        root_panel.add(option_bar, BorderLayout.SOUTH);
        center_list = new JPanel();
        center_list.setLayout(new BorderLayout(0, 0));
        root_panel.add(center_list, BorderLayout.CENTER);
        right_panel = new JPanel();
        right_panel.setLayout(new BorderLayout(0, 0));
        right_panel.setPreferredSize(new Dimension(442, 1));
        root_panel.add(right_panel, BorderLayout.EAST);
    }

    /**
     * @noinspection ALL
     */
    public JComponent $$$getRootComponent$$$() {
        return root_panel;
    }
}
